/** \file    refine/grey_mask_topology_limits.cpp
  * \brief   Calculates limits on mask's value to change that will not change topology of mask.
  * \date    2003
  * \author  Fedor Chelnokov
  * \version $Header: /home/cscom1r4/cvsroot/cs/refine/grey_mask_topology_limits.cpp,v 1.1 2004/02/04 14:43:24 cscom1r4 Exp $
  */

#include "imglib/imageclass.h"
typedef mono_byte_image	mask;
typedef mask::elem_type	mask_value;

namespace refine {

namespace grey_mask {

typedef mask::elem_type	mask_value;

struct minimizer {
	mask_value operator() (mask_value a, mask_value b) const
		{ return std::min(a, b); }
	mask_value operator() (mask_value a, mask_value b, mask_value c) const
		{ return std::min(std::min(a, b), c); }
};

struct maximizer {
	mask_value operator() (mask_value a, mask_value b) const
		{ return std::max(a, b); }
	mask_value operator() (mask_value a, mask_value b, mask_value c) const
		{ return std::max(std::min(a, b), c); }
};

static const int_point nei_points[7] = {
	//int_point(+1,  0),
	int_point(+1, +1),
	int_point( 0, +1),
	int_point(-1, +1),
	int_point(-1,  0),
	int_point(-1, -1),
	int_point( 0, -1),
	int_point(+1, -1)
};

template <class M, class OP, class AP>
mask_value limit(const M & m, int_point p, OP op, AP ap)
{
	mask_value v1 = m[size_point(p + int_point(0,-1))];
	mask_value v2 = m[size_point(p + int_point(1,-1))];
	mask_value v3 = m[size_point(p + int_point(1,0))];
	mask_value v = ap(v1, v2, v3);
	for (unsigned n = 0; n != 7; ++n) {
		v1 = v2;
		v2 = v3;
		v3 = m[size_point(p + nei_points[n])];
		v = op(v, ap(v1, v2, v3));
	}
	return v;
}

template <class M>
void topology_limits(mask_value & min, mask_value & max, const M & m, size_point p)
{
	max = limit(m, p, maximizer(), minimizer());
	min = limit(m, p, minimizer(), maximizer());
}

template 
void topology_limits(mask_value & min, mask_value & max, const mask & m, size_point p);

template 
void topology_limits(mask_value & min, mask_value & max, 
	const img::projection_raster<byte_image, mask_value> & m, size_point p);

} //namespace grey_mask

} //namespace refine
